import { renderToString, renderToStaticMarkup } from 'react-dom/server'
import { persistStore } from 'redux-persist';
import { createFilter } from 'redux-persist-transform-filter';
import { match, createMemoryHistory } from 'dva/router';
import * as Cookies from 'cookies';
import { routes } from '../src/router';
import createApp from './createApp';
import { Logger, settings, CookieStorage } from '../src/utils';

// redux-persist-transform-filter filter
const appSubsetFilter = createFilter(
  'app',
  ['siderFold', 'darkTheme', 'isNavbar', 'navOpenKeys'],
);
// logger
const logger = Logger.get('render_ssrMiddleware');
/**
 * 服务器端渲染调用方的转参
 */
interface RenderReq {
  path: string,
  serializedProps: any,
  toStaticMarkup: boolean
}

/**
 * 服务器端渲染返回子用的接口
 */
interface RenderRes {
  markup: string,
  initialState: any,
  error: {
    type: string,
    message: string,
    stack: string
  } | string
}

export default function(req, res, next) {
  logger.log(req.body);
  const { path, serializedProps, toStaticMarkup } = req.body as RenderReq;
  let props = {};
  // 取得参数，反序列化为json
  if (serializedProps) {
    props = JSON.parse(serializedProps);
  }
  match({
    routes,
    location: path,
  }, (err, redirectLocation, renderProps) => {
    if (err) {
      // res.status(500).end(`Internal Server Error ${err}`);
      res.json(getRes(err));
    } else if (redirectLocation) {
      res.redirect(302, redirectLocation.pathname + redirectLocation.search);
    } else if (renderProps) {
      // store的初始状态
      let initialState = {
        app: {
          isRendered: true,
          user: {}
        }
      };
      let app, html, context, persistConfig;
      const extraEnhancers = [];
      // 取得cookie
      const cookies = new Cookies(req, res);
      switch (renderProps.location.pathname) {
        //case '/':
        //  res.end('React render server');
        //  break;
        case '/login':
          // 登陆的状况,initialState 为空
          app = createApp({
            history: createMemoryHistory(),
            initialState
          }, /* isServer */settings.isServer, cookies);
          app.start()({ renderProps });
          // redux-persist config
          persistConfig = {
            transforms: [
              appSubsetFilter,
            ],
            storage: new CookieStorage(app._store.dispatch)
          };
          persistStore(app._store, persistConfig, ()=> {
            // 与cookie同步store状态
            context = app._getProvider(app._router)({ renderProps });
            html = toStaticMarkup? renderToStaticMarkup(context):
                renderToString(context);
            // 同步完后返回渲染结果
            res.json(getRes(null, html, initialState));
          });
          break;
        case '/dashboard':
        case '/':
          app = createApp({
            history: createMemoryHistory(),
            initialState
          }, /* isServer */settings.isServer, cookies);
          app.start()({ renderProps });
          persistConfig = {
            transforms: [
              appSubsetFilter,
            ],
            storage: new CookieStorage(app._store.dispatch)
          };
          persistStore(app._store, persistConfig, ()=> {
            // 与cookie同步store状态
            context = app._getProvider(app._router)({ renderProps });
            html = toStaticMarkup? renderToStaticMarkup(context):
                renderToString(context);
            // 同步完后返回渲染结果
            res.json(getRes(null, html, initialState));
          });
          break;
        default:
          // res.status(500).end(`Uncaught pathname: ${renderProps.location.pathname}`);
          res.json(getRes({
            type: '500',
            message: `Uncaught pathname: ${renderProps.location.pathname}`,
            stack: null
          }));
          break;
      }
    } else {
      res.status(404).send('Not found')
    }
  });
  // next();
}

function getRes(err, markup=null, initialState=null): RenderRes  {
  if (err) {
			return {
				error: {
					type: err.constructor.name,
					message: err.message,
					stack: err.stack
				},
				markup: null,
        initialState: null
			};
  } else {
    return {
      error: null,
      markup: renderFullPage(markup, initialState),
      initialState
    };
  }
}

function renderFullPage(html, initialState) {
  return `
<!DOCTYPE html>
<html lang="zh">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Dva Demo</title>
  <link rel="stylesheet" href="/static/index.css" />
</head>
<body>
  <div id="root">
    <div>
      ${html}
    </div>
  </div>
  <script>
    window.__INITIAL_STATE__ = ${JSON.stringify(initialState)};
  </script>
  <script src="/static/index.js"></script>
</body>
</html>
  `;
}
